先看简化后代码,下面只列出main函数
1 | func main() { |
这么看的话感觉两个SQL应该是相同的:
1 | [ORM] - 2017-01-19 19:28:02 - [Queries/default] - [ OK / db.Exec / 1.2ms] - [SELECT COUNT(*) FROM test WHERE create_time > ?] - `2017-01-19 00:00:00` |
我在本机测试OK,但在另一个环境SQL是这样的:
1 | [ORM] - 2017-01-19 11:30:43 - [Queries/default] - [ OK / db.Exec / 1.2ms] - [SELECT COUNT(*) FROM test WHERE create_time > ?] - `2017-01-19 00:00:00` |
相差8小时,第一时间想到时区问题,去有问题的环境一看果真如此。
然后看了下beego orm的代码,下面列出关键部分。
1.orm/db_utils.go
的getFlatParams()
此函数是解析Filter()
生成SQL的关键部分,如果Filter()
第一个参数类型是Date或Datetime,第二个参数类型是string就把string解析成time.Time类型
在上面case中len(v) = 19
,执行time.ParseInLocation(formatDateTime, s, DefaultTimeLoc)
,因为有问题的环境是UTC时区,所以此函数会把字符串2017-01-19 00:00:00
解析成time.Time2017-01-19 00:00:00 +0000 UTC
(变量t,但实际是东八区的时间,正确的t应该是2017-01-19 00:00:00 +0800 CST
)。
1 | func getFlatParams(fi *fieldInfo, args []interface{}, tz *time.Location) (params []interface{}) { |
2.t.In(tz).Format(formatDateTime)
再次将t格式化为字符串,参数tz
是关键,它是在下面代码中赋值的。因为MySQL设置的是东八区,所以会设置al.TZ为东八区,也就是t.In(tz).Format(formatDateTime)
中tz是东八区,导致Format
返回的字符串是2017-01-19 08:00:00
,于是就有了上面两条SQL不同的问题。
1 | func detectTZ(al *alias) { |